home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / faq-s.zip / STACK5.PAS < prev    next >
Pascal/Delphi Source File  |  1991-03-13  |  5KB  |  131 lines

  1. {***********************************************************
  2.   Stack5 - A unit to report stack usage information
  3.  
  4.   by Richard S. Sadowsky
  5.   version 2.0 10/16/88
  6.   for Turbo Pascal version 5.0
  7.   released to the public domain
  8.  
  9.   Inspired by an idea by Kim Kokkonen and Brian Foley.
  10.  
  11.   This unit, when used in a Turbo Pascal 5.0 program, will
  12.   automatically report information about stack usage.  This
  13.   is very useful during program development.  The following
  14.   information is reported about the stack automatically when
  15.   the program terminates (just add this unit to your USES
  16.   clause):
  17.  
  18.   Total stack space
  19.   Unused stack space
  20.   Stack spaced used by your program
  21.  
  22.   This unit is extremely similar to the file STKUSE.ARC
  23.   in BPROGA LIB 6 on Compuserve.  The difference is that
  24.   this file has been adapted for use with Turbo Pascal 5,
  25.   whereas STKUSE works with TP4.  Since this program
  26.   uses a hacker's technique to get the total stack value,
  27.   it is somewhat version specific.
  28.  
  29.   The unit's initialization code handles three things, it
  30.   figures out the total stack space, it initializes the
  31.   unused stack space to a known value, and it sets up an
  32.   ExitProc to automatically report the stack usage at
  33.   termination.  The total stack space is calculated by
  34.   adding 8 to the current stack pointer on entry into
  35.   the unit.
  36.  
  37.   The ExitProc StackReport handles the math of calculating
  38.   the used and unused amount of stack space, and displays
  39.   this information.  Note that the original ExitProc
  40.   (Sav_ExitProc) is restored immediately on entry to
  41.   StackReport.  This is a good idea in ExitProc in case
  42.   a runtime (or I/O) error occurs in your ExitProc!
  43.  
  44.   Despite the fact that Brian Foley has pointed out some
  45.   flaws in the method's used by this program, and uploaded
  46.   his own TPSTACK unit which handles things somewhat
  47.   differently (and also reports heap usage), I've decided to
  48.   post this update.  The reason is that Brian's TPStack
  49.   reprograms the timer, and therefore can't be used (as
  50.   currently implemented) with other units or programs
  51.   that reprogram the timer.  While in development, I often
  52.   use TPTimer for high resolution timing, but also need to
  53.   know the stack usage.  The main flaw in my technique
  54.   that Brian has pointed out is that it will not catch
  55.   stack space reserved by a routine but not used.
  56.   Consider the following:
  57.  
  58.   procedure EatTheStack;
  59.   var
  60.     BigLocalVar    : Array[1..MAXINT] of Char;
  61.   begin
  62.   end;
  63.  
  64.   Stack5 will not show that this massive variable used
  65.   any stack space (which of course it does, MAXINT chars
  66.   worth) because the values in BigLocalVar have not been
  67.   modified.  Since I generally use any variables I declare
  68.   (otherwise why waste the space), this doesn't present
  69.   a major problem for me in most applications.  In apps
  70.   where it matters, I use Brian's TPStack, which reprograms
  71.   the timer to tick more frequently, and "samples" the stack
  72.   and heap sizes.  Since SP is actually examined, his
  73.   technique will show the above BigLocalVar's stack usage.
  74.  
  75.   I hope you find this unit as useful as I have!
  76.  
  77. ***********************************************************}
  78. {$R-,S-} { we don't need no stinkin range or stack checking! }
  79. unit Stack5;
  80.  
  81. interface
  82.  
  83. const
  84.   StackInitValue   = $AA; { the value to initialize the stack to. }
  85.   SAFETY           = 20;  { This value is used as a safety buffer }
  86.                           { when initializing the stack to the    }
  87.                           { StackInitValue.  This default of 20   }
  88.                           { is safe and shouldn't be lowered.     }
  89. var
  90.   Sav_ExitProc     : Pointer; { to save the previous ExitProc }
  91.   StartSPtr        : Word;    { holds the total stack size    }
  92.  
  93. implementation
  94.  
  95. {$F+} { this is an ExitProc so it must be compiled as far }
  96. procedure StackReport;
  97.  
  98. { This procedure may take a second or two to execute, especially }
  99. { if you have a large stack. The time is spent examining the     }
  100. { stack looking for our init value (StackInitValue). }
  101.  
  102. var
  103.   I                : Word;
  104.  
  105. begin
  106.   ExitProc := Sav_ExitProc; { restore original exitProc first }
  107.  
  108.   I := 0;
  109.   { step through stack from bottom looking for StackInitValue,}
  110.   { stop when found }
  111.   while I < SPtr do
  112.     if Mem[SSeg:I] <> StackInitValue then begin
  113.       { found StackInitValue so report the stack usage info }
  114.       WriteLn;
  115.       WriteLn('Total stack space : ',StartSPtr);
  116.       WriteLn('Unused stack space: ', I);
  117.       WriteLn('Stack space used  : ',StartSPtr - I);
  118.       I := SPtr; { end the loop }
  119.     end
  120.     else
  121.       inc(I); { look in next byte }
  122. end;
  123. {$F-}
  124.  
  125. begin
  126.   StartSPtr := SPtr + 8;  { grab the current SP and account for used space }
  127.   FillChar(Mem[SSeg:0], SPtr - SAFETY, StackInitValue); { init the stack   }
  128.   Sav_ExitProc := ExitProc;                             { save exitproc    }
  129.   ExitProc     := @StackReport;                         { set our exitproc }
  130. end.
  131.